﻿namespace Atomic.Mvc
{
    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;

    using Autofac;

    using Atomic.Data;
    using Atomic.Caching;
    using Atomic.Messages;
    using Atomic.Plugins;
    using Atomic.Plugins.Files;
    using Atomic.Mvc;
    using Atomic.Mvc.Themes;
    using Atomic.Mvc.Filters;
    using Atomic.Mvc.Controllers;
    using Atomic.Mvc.ViewEngines;
    using Atomic.Mvc.ModelBinders;
    using System.Collections.Generic;

    /// <summary>
    /// 预启动程序。
    /// </summary>
    public class Starter
    {
        /// <summary>
        /// 预启动程序。
        /// </summary>
        private static Starter _starter = null;

        /// <summary>
        /// 锁。
        /// </summary>
        private readonly static object _lockObject = new object();

        /// <summary>
        /// 初始化的外部委托。
        /// </summary>
        private readonly Action<ContainerBuilder> _initialization = null;

        /// <summary>
        /// 初始化预启动程序。
        /// </summary>
        /// <param name="initialization">委托方法。</param>
        public Starter(Action<ContainerBuilder> initialization)
        {
            this._initialization = initialization;
        }

        /// <summary>
        /// 创建预启动程序。
        /// </summary>
        /// <returns>预启动程序。</returns>
        public static Starter CreateStarter()
        {
            return CreateStarter(builder => { });
        }

        /// <summary>
        /// 创建预启动程序。
        /// </summary>
        /// <param name="initialization">委托方法。</param>
        /// <returns>预启动程序。</returns>
        public static Starter CreateStarter(Action<ContainerBuilder> initialization)
        {
            if(_starter == null)
            {
                lock(_lockObject)
                {
                    if(_starter == null)
                    {
                        _starter = new Starter(initialization);
                    }
                }
            }

            return _starter;
        }

        /// <summary>
        /// 应用程序启动。
        /// </summary>
        /// <param name="application">应用程序启动。</param>
        public void OnApplicationStart(HttpApplication application)
        {
            var builder = new ContainerBuilder();

            //注册 MVC 控制器。
            builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
                .Where(t => typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller", StringComparison.Ordinal));

            //缓存。
            builder.RegisterType<DefaultCacheManager>().As<ICacheManager>().SingleInstance();

            ////数据。
            //builder.Register<IDbContext>(context => new AtomicObjectContext()).InstancePerHttpRequest();
            //builder.RegisterGeneric(typeof(EFRepository<>)).As(typeof(IEFRepository<>)).InstancePerHttpRequest();

            //环境。
            builder.RegisterType<DefaultAssemblyLoader>().As<IAssemblyLoader>().SingleInstance();
            builder.RegisterType<DefaultAssemblyProbingFolder>().As<IAssemblyProbingFolder>().SingleInstance();

            //文件系统。
            builder.RegisterType<DefaultVirtualPathProvider>().As<IVirtualPathProvider>().SingleInstance();

            builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
            builder.RegisterType<DefaultRzaorViewEngineProvider>().As<IRzaorViewEngineProvider>();

            ////插件系统。
            //builder.RegisterType<DefaultManifestManager>().As<IManifestManager>().SingleInstance();
            //builder.RegisterType<PluginHarvester>().As<IPluginHarvester>().SingleInstance();
            //builder.RegisterType<CoreFolder>().As<IPluginFolder>().SingleInstance();
            //builder.RegisterType<PluginFolder>().As<IPluginFolder>().SingleInstance();
            //builder.RegisterType<WebPluginInitializer>().As<IPluginInitializer>().SingleInstance();
            //builder.RegisterType<DefaultPluginLoader>().As<IPluginLoader>().SingleInstance();
            //builder.RegisterType<DefaultPluginManager>().As<IPluginManager>().SingleInstance();

            //模板引擎。
            builder.RegisterType<DefaultPartManager>().As<IPartManager>().SingleInstance();
            builder.RegisterType<DefaultLayoutManager>().As<ILayoutManager>().SingleInstance();

            //注册外部方法。
            this._initialization(builder);

            var container = builder.Build();

            //初始化容器。
            AtomicContainer.RegisterContainer(new DefaultAtomicContainer(container));

            //注册消息事件。
            MessageFactory.SetMessageBus(new DefaultMessageBus(GetMessageHandlers));

            //激活插件。
            this.EnabledPlugins(container);

            //注册控制器工厂。
            ControllerBuilder.Current.SetControllerFactory(new AtomicControllerFactory());

            //注册视图引擎。
            System.Web.Mvc.ViewEngines.Engines.Clear();
            System.Web.Mvc.ViewEngines.Engines.Add(new ViewEngineCollectionWrapper(container.Resolve<IRzaorViewEngineProvider>()));

            //注册模型绑定器。
            System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new AtomicModelBinder();

            //注册过滤器。
            GlobalFilters.Filters.Add(new ViewAttribute());
        }

        /// <summary>
        /// 激活插件。
        /// </summary>
        private void EnabledPlugins(IContainer container)
        {
            var pluginManager = this.CreatePluginManager(container);

            PluginManager.Current.EnabledPlugins();
        }

        /// <summary>
        /// 创建插件管理器。
        /// </summary>
        /// <param name="container">容器。</param>
        /// <returns>插件管理器。</returns>
        private IPluginManager CreatePluginManager(IContainer container)
        {
            var assemblyProbingFolder = container.Resolve<IAssemblyProbingFolder>();
            var layoutManager = container.Resolve<ILayoutManager>();
            var partManager = container.Resolve<IPartManager>();

            PluginManager.Initialize(new WebPluginInitializer(assemblyProbingFolder, layoutManager, partManager));

            return PluginManager.Current;
        }

        /// <summary>
        /// 获得所有消息处理程序。
        /// </summary>
        /// <returns>消息处理程序集合。</returns>
        private IEnumerable<IMessageHandler> GetMessageHandlers()
        {
            return AtomicContainer.Resolve<IEnumerable<IMessageHandler>>();
        }
    }
}